use super::*;
use crate::infra::*;
use serde_json::to_string;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::Mutex;
use wd_run::Context;

#[derive(Clone)]
pub struct Entity {
    builder: Arc<dyn EntryPointBuilder>,
    controls: Arc<Mutex<HashMap<String, Box<dyn ControlPanel>>>>,
}

impl Entity {
    pub fn new<B>(builder: B, cfg: Vec<EntryPoint>) -> Result<Self>
    where
        B: EntryPointBuilder,
    {
        let builder = Arc::new(builder);
        let mut controls = HashMap::new();
        for endpoint in cfg.clone() {
            let name = endpoint.name.clone();
            let ctl = Self::build_entry_point(endpoint, builder.clone())?;
            controls.insert(name, ctl);
        }
        let controls = Arc::new(Mutex::new(controls));
        Ok(Self { builder, controls })
    }
    #[allow(dead_code)]
    pub fn event_dispenser(&self) -> impl ControlEventDispenser {
        self.clone()
    }
    pub async fn close(&mut self) {
        let mut ctls = self.controls.lock().await;
        for (name, cp) in ctls.iter_mut() {
            match cp.stop(Context::new()).await {
                Ok(_o) => wd_log::log_info_ln!("入口服务[{}]关闭成功", name),
                Err(e) => wd_log::log_error_ln!("入口服务[{}]关闭失败{}", name, e.to_string()),
            }
        }
    }

    pub fn build_entry_point(
        cfg: EntryPoint,
        builder: Arc<dyn EntryPointBuilder>,
    ) -> Result<Box<dyn ControlPanel>> {
        let name = cfg.name.clone();
        let (mut ser, ctl) = builder.build(cfg)?;
        go(async move {
            if let Err(e) = ser.run().await {
                wd_log::log_error_ln!("服务[{}]运行错误：{}", name, e.to_string());
            } else {
                // wd_log::log_info_ln!("服务[{}]运行结束", name);
            }
        });
        Ok(ctl)
    }
    async fn dispatch_build_entry_point(
        &self,
        ctx: Context,
        cfg: EntryPoint,
    ) -> Result<Option<OptResponse>> {
        let mut ctls = self.controls.lock().await;
        let ctl = match ctls.get_mut(&cfg.name) {
            Some(s) => s,
            None => {
                let name = cfg.name.clone();
                let ctl = Entity::build_entry_point(cfg.clone(), self.builder.clone())?;
                ctls.insert(name, ctl);
                wd_log::log_info_ln!(
                    "服务创建成功：{}",
                    serde_json::to_string(&cfg)
                        .unwrap_or_else(|e| format!("json error:{}", e.to_string()))
                );
                return Ok(None);
            }
        };
        let old_cfg = ctl.config(ctx.clone());
        if Self::need_reboot(old_cfg.as_ref(), &cfg) {
            if let Err(err) = ctl.stop(ctx).await {
                wd_log::log_error_ln!(
                    "在更新entrypoint服务时，关闭原服务失败，error:{}",
                    err.to_string()
                );
            }
            let name = cfg.name.clone();
            let ctl = Entity::build_entry_point(cfg.clone(), self.builder.clone())?;
            ctls.insert(name, ctl);
            wd_log::log_info_ln!(
                "服务更新成功：{}",
                serde_json::to_string(&cfg)
                    .unwrap_or_else(|e| format!("json error:{}", e.to_string()))
            );
        } else {
            wd_log::log_info_ln!(
                "检测到服务不需要更新：{}",
                to_string(&cfg).unwrap_or(String::new())
            );
        }
        Ok(None)
    }
    fn need_reboot(old: &EntryPoint, new: &EntryPoint) -> bool {
        if old.addr != new.addr {
            return true;
        }
        if old.ty != new.ty {
            return true;
        }
        if old.ca_file != new.ca_file {
            return true;
        }
        if old.private_key != new.private_key {
            return true;
        }
        return false;
    }
}

#[async_trait::async_trait]
impl ControlEventDispenser for Entity {
    async fn dispatch(&self, ce: ControlEvent) -> Result<Option<OptResponse>> {
        wd_log::log_info_ln!("接收到一个事件：kind:{}", ce.kind);
        match ce.kind {
            EventKind::BuildEP(cfg) => {
                return self.dispatch_build_entry_point(ce.context, cfg).await;
            }
            EventKind::RemoveEP(name) => {
                let mut ctls = self.controls.lock().await;
                if let Some(mut ctl) = ctls.remove(&name) {
                    return ctl.stop(ce.context).await;
                }
            }
            EventKind::Operation(name) => {
                let mut ctls = self.controls.lock().await;
                let ctl = match ctls.get_mut(&name) {
                    Some(s) => s,
                    None => return Ok(None),
                };
                match ce.opt {
                    Operation::Router(rt) => return ctl.router(ce.context, rt).await,
                    Operation::Ip(ips) => {
                        return ctl.ip_filter(ce.context, ips).await.map(|_| None)
                    }
                    Operation::None => {}
                }
            }
            EventKind::StopDispenser => {}
            EventKind::Error(_err) => {}
            EventKind::Other => {}
        }
        Ok(None)
    }
}
